"""
工作流节点定义

定义各种类型的工作流节点和它们的行为。
"""

import uuid
from abc import ABC, abstractmethod
from typing import Dict, Any, List, Optional, Callable, Union
from enum import Enum
from datetime import datetime
import logging

from src.core.di import Injectable


class NodeStatus(Enum):
    """节点状态枚举"""
    PENDING = "pending"          # 等待执行
    RUNNING = "running"          # 正在执行
    COMPLETED = "completed"      # 执行完成
    FAILED = "failed"           # 执行失败
    SKIPPED = "skipped"         # 跳过执行
    CANCELLED = "cancelled"     # 取消执行


class NodeType(Enum):
    """节点类型枚举"""
    INPUT = "input"             # 输入节点
    OUTPUT = "output"           # 输出节点
    PROCESSING = "processing"   # 处理节点
    CONDITIONAL = "conditional" # 条件节点
    PARALLEL = "parallel"       # 并行节点
    SEQUENTIAL = "sequential"   # 顺序节点


class WorkflowNode(ABC):
    """
    工作流节点基类
    
    定义所有工作流节点的基本接口和行为。
    """
    
    def __init__(self,
                 node_id: str = None,
                 name: str = None,
                 description: str = None,
                 config: Dict[str, Any] = None):
        self.node_id = node_id or str(uuid.uuid4())
        self.name = name or f"{self.__class__.__name__}_{self.node_id[:8]}"
        self.description = description or ""
        self.config = config or {}
        
        # 节点状态
        self.status = NodeStatus.PENDING
        self.error_message = None
        self.start_time = None
        self.end_time = None
        
        # 连接关系
        self.inputs: List['WorkflowNode'] = []
        self.outputs: List['WorkflowNode'] = []
        
        # 数据
        self.input_data: Dict[str, Any] = {}
        self.output_data: Dict[str, Any] = {}
        
        # 日志
        self.logger = logging.getLogger(f"workflow.{self.__class__.__name__}")
    
    @property
    @abstractmethod
    def node_type(self) -> NodeType:
        """节点类型"""
        pass
    
    @abstractmethod
    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """
        执行节点逻辑
        
        Args:
            context: 工作流执行上下文
            
        Returns:
            执行结果数据
        """
        pass
    
    def add_input(self, node: 'WorkflowNode') -> None:
        """添加输入节点"""
        if node not in self.inputs:
            self.inputs.append(node)
            if self not in node.outputs:
                node.outputs.append(self)
    
    def add_output(self, node: 'WorkflowNode') -> None:
        """添加输出节点"""
        if node not in self.outputs:
            self.outputs.append(node)
            if self not in node.inputs:
                node.inputs.append(self)
    
    def remove_input(self, node: 'WorkflowNode') -> None:
        """移除输入节点"""
        if node in self.inputs:
            self.inputs.remove(node)
            if self in node.outputs:
                node.outputs.remove(self)
    
    def remove_output(self, node: 'WorkflowNode') -> None:
        """移除输出节点"""
        if node in self.outputs:
            self.outputs.remove(node)
            if self in node.inputs:
                node.inputs.remove(self)
    
    def set_input_data(self, data: Dict[str, Any]) -> None:
        """设置输入数据"""
        self.input_data.update(data)
    
    def get_output_data(self) -> Dict[str, Any]:
        """获取输出数据"""
        return self.output_data.copy()
    
    def reset(self) -> None:
        """重置节点状态"""
        self.status = NodeStatus.PENDING
        self.error_message = None
        self.start_time = None
        self.end_time = None
        self.input_data.clear()
        self.output_data.clear()
    
    def start_execution(self) -> None:
        """开始执行"""
        self.status = NodeStatus.RUNNING
        self.start_time = datetime.utcnow()
        self.logger.info(f"节点开始执行: {self.name}")
    
    def complete_execution(self, output_data: Dict[str, Any] = None) -> None:
        """完成执行"""
        self.status = NodeStatus.COMPLETED
        self.end_time = datetime.utcnow()
        if output_data:
            self.output_data.update(output_data)
        self.logger.info(f"节点执行完成: {self.name}")
    
    def fail_execution(self, error_message: str) -> None:
        """执行失败"""
        self.status = NodeStatus.FAILED
        self.end_time = datetime.utcnow()
        self.error_message = error_message
        self.logger.error(f"节点执行失败: {self.name} - {error_message}")
    
    def skip_execution(self, reason: str = None) -> None:
        """跳过执行"""
        self.status = NodeStatus.SKIPPED
        self.end_time = datetime.utcnow()
        if reason:
            self.error_message = reason
        self.logger.info(f"节点跳过执行: {self.name} - {reason or 'No reason'}")
    
    def cancel_execution(self) -> None:
        """取消执行"""
        self.status = NodeStatus.CANCELLED
        self.end_time = datetime.utcnow()
        self.logger.info(f"节点取消执行: {self.name}")
    
    @property
    def duration(self) -> Optional[float]:
        """执行时长（秒）"""
        if self.start_time and self.end_time:
            return (self.end_time - self.start_time).total_seconds()
        return None
    
    @property
    def is_ready(self) -> bool:
        """是否准备好执行"""
        # 检查所有输入节点是否已完成
        for input_node in self.inputs:
            if input_node.status not in [NodeStatus.COMPLETED, NodeStatus.SKIPPED]:
                return False
        return True
    
    @property
    def is_finished(self) -> bool:
        """是否已完成执行"""
        return self.status in [NodeStatus.COMPLETED, NodeStatus.FAILED, NodeStatus.SKIPPED, NodeStatus.CANCELLED]
    
    def validate_config(self) -> List[str]:
        """验证节点配置"""
        errors = []
        
        # 基本验证
        if not self.name:
            errors.append("节点名称不能为空")
        
        return errors
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'node_id': self.node_id,
            'name': self.name,
            'description': self.description,
            'node_type': self.node_type.value,
            'status': self.status.value,
            'config': self.config,
            'input_data': self.input_data,
            'output_data': self.output_data,
            'error_message': self.error_message,
            'start_time': self.start_time.isoformat() if self.start_time else None,
            'end_time': self.end_time.isoformat() if self.end_time else None,
            'duration': self.duration,
            'inputs': [node.node_id for node in self.inputs],
            'outputs': [node.node_id for node in self.outputs]
        }


class InputNode(WorkflowNode):
    """
    输入节点
    
    工作流的数据输入点。
    """
    
    @property
    def node_type(self) -> NodeType:
        return NodeType.INPUT
    
    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """执行输入节点"""
        self.start_execution()
        
        try:
            # 从配置或上下文获取输入数据
            input_data = self.config.get('data', {})
            
            # 如果配置中指定了数据源
            if 'data_source' in self.config:
                data_source = self.config['data_source']
                if hasattr(context, data_source):
                    input_data.update(getattr(context, data_source))
            
            # 合并输入数据
            input_data.update(self.input_data)
            
            self.complete_execution(input_data)
            return input_data
            
        except Exception as e:
            self.fail_execution(str(e))
            raise


class OutputNode(WorkflowNode):
    """
    输出节点
    
    工作流的数据输出点。
    """
    
    @property
    def node_type(self) -> NodeType:
        return NodeType.OUTPUT
    
    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """执行输出节点"""
        self.start_execution()
        
        try:
            # 收集所有输入节点的输出数据
            output_data = {}
            for input_node in self.inputs:
                output_data.update(input_node.get_output_data())
            
            # 应用输出过滤器
            if 'output_filter' in self.config:
                filter_keys = self.config['output_filter']
                if isinstance(filter_keys, list):
                    output_data = {k: v for k, v in output_data.items() if k in filter_keys}
            
            # 保存到上下文
            if 'output_key' in self.config:
                context.set_data(self.config['output_key'], output_data)
            
            self.complete_execution(output_data)
            return output_data
            
        except Exception as e:
            self.fail_execution(str(e))
            raise


class ProcessingNode(WorkflowNode):
    """
    处理节点
    
    执行具体的处理逻辑。
    """
    
    def __init__(self,
                 processor: Callable = None,
                 **kwargs):
        super().__init__(**kwargs)
        self.processor = processor
    
    @property
    def node_type(self) -> NodeType:
        return NodeType.PROCESSING
    
    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """执行处理节点"""
        self.start_execution()
        
        try:
            # 收集输入数据
            input_data = {}
            for input_node in self.inputs:
                input_data.update(input_node.get_output_data())
            input_data.update(self.input_data)
            
            # 执行处理器
            if self.processor:
                if asyncio.iscoroutinefunction(self.processor):
                    result = await self.processor(input_data, context, self.config)
                else:
                    result = self.processor(input_data, context, self.config)
            else:
                # 默认处理：直接传递数据
                result = input_data
            
            # 确保结果是字典
            if not isinstance(result, dict):
                result = {'result': result}
            
            self.complete_execution(result)
            return result
            
        except Exception as e:
            self.fail_execution(str(e))
            raise
    
    def validate_config(self) -> List[str]:
        """验证处理节点配置"""
        errors = super().validate_config()
        
        if not self.processor and 'processor' not in self.config:
            errors.append("处理节点必须指定处理器")
        
        return errors


class ConditionalNode(WorkflowNode):
    """
    条件节点
    
    根据条件决定执行路径。
    """
    
    def __init__(self,
                 condition: Callable = None,
                 **kwargs):
        super().__init__(**kwargs)
        self.condition = condition
        self.true_outputs: List[WorkflowNode] = []
        self.false_outputs: List[WorkflowNode] = []
    
    @property
    def node_type(self) -> NodeType:
        return NodeType.CONDITIONAL
    
    def add_true_output(self, node: WorkflowNode) -> None:
        """添加条件为真时的输出节点"""
        if node not in self.true_outputs:
            self.true_outputs.append(node)
            self.add_output(node)
    
    def add_false_output(self, node: WorkflowNode) -> None:
        """添加条件为假时的输出节点"""
        if node not in self.false_outputs:
            self.false_outputs.append(node)
            self.add_output(node)
    
    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """执行条件节点"""
        self.start_execution()
        
        try:
            # 收集输入数据
            input_data = {}
            for input_node in self.inputs:
                input_data.update(input_node.get_output_data())
            input_data.update(self.input_data)
            
            # 评估条件
            condition_result = False
            if self.condition:
                if asyncio.iscoroutinefunction(self.condition):
                    condition_result = await self.condition(input_data, context, self.config)
                else:
                    condition_result = self.condition(input_data, context, self.config)
            elif 'condition' in self.config:
                # 简单的条件表达式评估
                condition_expr = self.config['condition']
                condition_result = self._evaluate_condition(condition_expr, input_data)
            
            # 设置执行路径
            result = {
                'condition_result': condition_result,
                'input_data': input_data,
                'execution_path': 'true' if condition_result else 'false'
            }
            
            self.complete_execution(result)
            return result
            
        except Exception as e:
            self.fail_execution(str(e))
            raise
    
    def _evaluate_condition(self, condition_expr: str, data: Dict[str, Any]) -> bool:
        """评估简单的条件表达式"""
        try:
            # 简单的条件评估（实际项目中应该使用更安全的表达式解析器）
            # 这里只是示例，支持基本的比较操作
            import operator
            
            ops = {
                '>': operator.gt,
                '<': operator.lt,
                '>=': operator.ge,
                '<=': operator.le,
                '==': operator.eq,
                '!=': operator.ne,
            }
            
            for op_str, op_func in ops.items():
                if op_str in condition_expr:
                    left, right = condition_expr.split(op_str, 1)
                    left = left.strip()
                    right = right.strip()
                    
                    # 获取左值
                    left_val = data.get(left, left)
                    if isinstance(left_val, str) and left_val.isdigit():
                        left_val = float(left_val)
                    
                    # 获取右值
                    right_val = right
                    if right.isdigit():
                        right_val = float(right)
                    elif right in data:
                        right_val = data[right]
                    
                    return op_func(left_val, right_val)
            
            # 如果没有操作符，检查布尔值
            if condition_expr in data:
                return bool(data[condition_expr])
            
            return bool(condition_expr)
            
        except Exception:
            return False


# 导入asyncio用于异步检查
import asyncio


class ParallelNode(WorkflowNode):
    """
    并行节点

    并行执行多个子节点。
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.child_nodes: List[WorkflowNode] = []

    @property
    def node_type(self) -> NodeType:
        return NodeType.PARALLEL

    def add_child(self, node: WorkflowNode) -> None:
        """添加子节点"""
        if node not in self.child_nodes:
            self.child_nodes.append(node)
            self.add_output(node)

    def remove_child(self, node: WorkflowNode) -> None:
        """移除子节点"""
        if node in self.child_nodes:
            self.child_nodes.remove(node)
            self.remove_output(node)

    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """执行并行节点"""
        self.start_execution()

        try:
            # 收集输入数据
            input_data = {}
            for input_node in self.inputs:
                input_data.update(input_node.get_output_data())
            input_data.update(self.input_data)

            # 为所有子节点设置输入数据
            for child in self.child_nodes:
                child.set_input_data(input_data)

            # 并行执行所有子节点
            tasks = []
            for child in self.child_nodes:
                task = asyncio.create_task(child.execute(context))
                tasks.append(task)

            # 等待所有任务完成
            results = await asyncio.gather(*tasks, return_exceptions=True)

            # 收集结果
            output_data = {
                'parallel_results': {},
                'input_data': input_data,
                'execution_summary': {
                    'total_nodes': len(self.child_nodes),
                    'successful_nodes': 0,
                    'failed_nodes': 0
                }
            }

            for i, (child, result) in enumerate(zip(self.child_nodes, results)):
                if isinstance(result, Exception):
                    output_data['parallel_results'][child.node_id] = {
                        'status': 'failed',
                        'error': str(result)
                    }
                    output_data['execution_summary']['failed_nodes'] += 1
                else:
                    output_data['parallel_results'][child.node_id] = {
                        'status': 'completed',
                        'data': result
                    }
                    output_data['execution_summary']['successful_nodes'] += 1

            self.complete_execution(output_data)
            return output_data

        except Exception as e:
            self.fail_execution(str(e))
            raise


class SequentialNode(WorkflowNode):
    """
    顺序节点

    按顺序执行多个子节点。
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.child_nodes: List[WorkflowNode] = []

    @property
    def node_type(self) -> NodeType:
        return NodeType.SEQUENTIAL

    def add_child(self, node: WorkflowNode) -> None:
        """添加子节点"""
        if node not in self.child_nodes:
            self.child_nodes.append(node)
            self.add_output(node)

    def remove_child(self, node: WorkflowNode) -> None:
        """移除子节点"""
        if node in self.child_nodes:
            self.child_nodes.remove(node)
            self.remove_output(node)

    def insert_child(self, index: int, node: WorkflowNode) -> None:
        """在指定位置插入子节点"""
        if node not in self.child_nodes:
            self.child_nodes.insert(index, node)
            self.add_output(node)

    async def execute(self, context: 'WorkflowContext') -> Dict[str, Any]:
        """执行顺序节点"""
        self.start_execution()

        try:
            # 收集输入数据
            input_data = {}
            for input_node in self.inputs:
                input_data.update(input_node.get_output_data())
            input_data.update(self.input_data)

            # 顺序执行所有子节点
            current_data = input_data.copy()
            sequential_results = []

            for i, child in enumerate(self.child_nodes):
                # 设置当前数据作为子节点的输入
                child.set_input_data(current_data)

                try:
                    # 执行子节点
                    result = await child.execute(context)

                    # 记录结果
                    sequential_results.append({
                        'node_id': child.node_id,
                        'node_name': child.name,
                        'status': 'completed',
                        'data': result,
                        'step': i + 1
                    })

                    # 更新当前数据（下一个节点的输入）
                    if isinstance(result, dict):
                        current_data.update(result)

                except Exception as e:
                    # 记录失败
                    sequential_results.append({
                        'node_id': child.node_id,
                        'node_name': child.name,
                        'status': 'failed',
                        'error': str(e),
                        'step': i + 1
                    })

                    # 根据配置决定是否继续
                    if not self.config.get('continue_on_error', False):
                        raise e

            # 构建输出数据
            output_data = {
                'sequential_results': sequential_results,
                'final_data': current_data,
                'input_data': input_data,
                'execution_summary': {
                    'total_steps': len(self.child_nodes),
                    'completed_steps': len([r for r in sequential_results if r['status'] == 'completed']),
                    'failed_steps': len([r for r in sequential_results if r['status'] == 'failed'])
                }
            }

            self.complete_execution(output_data)
            return output_data

        except Exception as e:
            self.fail_execution(str(e))
            raise
